package com.yyl.fmall.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yyl.fmall.order.entity.OrderItem;
import com.yyl.fmall.order.entity.Orders;
import com.yyl.fmall.order.mapper.OrdersMapper;
import com.yyl.fmall.order.service.IOrderItemService;
import com.yyl.fmall.order.service.IOrdersService;
import com.yyl.fmall.order.utils.OrderConstants;
import com.yyl.fmall.order.vo.AddOrderReturnVo;
import com.yyl.fmall.product.entity.ProductSku;
import com.yyl.fmall.product.service.IProductSkuService;
import com.yyl.fmall.shopcart.entity.ShoppingCart;
import com.yyl.fmall.shopcart.service.IShoppingCartService;
import com.yyl.fmall.user.exception.IllegalCharacterException;
import com.yyl.fmall.utils.WxpayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @BelongsProject: fmall
 * @BelongsPackage: com.yyl.fmall.order.service.impl
 * @Author: YuanSir
 * @CreateTime: 2022-11-09  14:14
 * @Description:
 * @Version: 1.0
 */


@Service
public class OrdersTeacherServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    
    @Autowired
    private IShoppingCartService shoppingCartService;
    
    
    @Autowired
    private IOrderItemService orderItemService;
    
    
    @Autowired
    private IProductSkuService productSkuService;
    
    
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized AddOrderReturnVo add(String cids, Orders orders) throws Exception {
    
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
        //1.cids ——> List<购物车对象（填充好了所有信息）>,用于生成订单明细表中的数据（快照）中的数据
        cids = cids.replaceAll("#", "");
        List<ShoppingCart> shoppingCartList = shoppingCartService.listByCids(cids);
    
        //1.5 验证库存量,并扣减库存
        checkStockNum(shoppingCartList);
        
        //2.保存订单主表信息
        String skuNames = shoppingCartList.stream()
                .map(ShoppingCart::getSkuName)
                .collect(Collectors.joining(","));
        
        
        orders.setStatus(OrderConstants.ORDER_TO_BE_PAID); //设置订单为未支付
        orders.setDeleteStatus(OrderConstants.ORDER_DEFAULT_DELETE); // 逻辑删除标记
        orders.setUntitled(skuNames);
        orders.setCreateTime(new Date());
        orders.setCancelTime(new Date());
        save(orders); //保存订单后会自动回填主键
        String orderId = orders.getOrderId();
    
        //3.保存订单明细表信息
        //List<ShoppingCart> ——> List<OrderItem>
        List<OrderItem> orderItemList = shoppingCartList.stream()
                .map(shoppingCart -> {
                
                    OrderItem orderItem = new OrderItem();
                    
                    orderItem.setOrderId(orderId);
                    
                    //把cart对象中同名属性拷贝
                    BeanUtils.copyProperties(shoppingCart, orderItem);
                    
                    orderItem.setBuyCounts(Integer.valueOf(shoppingCart.getCartNum()));
                    
                    orderItem.setTotalAmount(
                            new BigDecimal(shoppingCart.getSellPrice())
                                    .multiply(new BigDecimal(shoppingCart.getCartNum())));
    
                    try {
                        orderItem.setBasketDate(simpleDateFormat.parse(shoppingCart.getCartTime()));
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
    
                    orderItem.setBuyTime(new Date());
                    
                    orderItem.setIsComment(OrderConstants.ORDER_NOT_EVALUATED);
                    
                    return orderItem;
                
                })
                .collect(Collectors.toList());
    
        orderItemService.saveBatch(orderItemList);
    
        //5.删除对应购物车
        shoppingCartService.removeByIds(shoppingCartList);
        
        //6.调用微信支付平台获取支付的Url
        String url = getWeiChatPayUrl(orders);
        
        return new AddOrderReturnVo(orderId, skuNames, url);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String status(String orderId) throws Exception {
        
        //1. 调用微信支付工具类查询订单状态
        String status = WxpayUtils.queryOrder(orderId);
        
        if (status != null && status.equals(OrderConstants.WX_PAY_OK)){
            
            //更改数据库中订单表中订单状态、时间戳
            Orders order = new Orders();
            
            order.setOrderId(orderId);
            order.setStatus(OrderConstants.PAY_OK_STATUS);
            order.setUpdateTime(new Date());
            order.setPayTime(new Date());
            
            updateById(order);
            
            return OrderConstants.ORDER_TO_BE_SHIPPED; //返回前端需要的成功状态字符串
            
        }
        
        return OrderConstants.PAY_NOT_OK_STATUS;
    
    }
    
    @Override
    @Scheduled(cron = "0/5 * * * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void deleteExpiredOrders() {
    
        Map<String, Orders> orderMap = list(new LambdaQueryWrapper<Orders>()
                .eq(Orders::getStatus, OrderConstants.ORDER_TO_BE_PAID)).stream()
                .collect(Collectors.toMap(Orders::getOrderId, orders -> orders));

        ArrayList<String> orderIdList = new ArrayList<>();

        orderMap.forEach((key, value) -> {

            if (DateUtil.betweenMs(value.getCreateTime(), new Date()) >= 1000 * 60 * 30) {

                orderIdList.add(key);

            } else {
                
                orderMap.remove(key);
                
            }

        });

        update(new LambdaUpdateWrapper<Orders>()
                .in(orderIdList.size() > 0, Orders::getOrderId, orderIdList)
                .set(Orders::getStatus, OrderConstants.ORDER_CLOSED));
    
        Map<String, Integer> productSkuIdBuyCountMap = orderItemService.list(new LambdaQueryWrapper<OrderItem>()
                        .in(orderIdList.size() > 0, OrderItem::getOrderId, orderIdList)).stream()
                .collect(Collectors.groupingBy(OrderItem::getSkuId, Collectors.summingInt(OrderItem::getBuyCounts)));
    
        List<String> productSkuIdList = productSkuIdBuyCountMap.entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList());
    
        List<ProductSku> productSkuList = productSkuService.list(new LambdaQueryWrapper<ProductSku>()
                .in(ProductSku::getSkuId, productSkuIdList));
        
        productSkuList.forEach(productSku -> productSku.setStock(productSku.getStock() + productSkuIdBuyCountMap.get(productSku.getSkuId())));
        
        productSkuService.updateBatchById(productSkuList);
        
        System.out.println(Thread.currentThread() + "：执行了！");
        
    }
    
    
    private String getWeiChatPayUrl(Orders orders) throws Exception {
    
        Map<String, Object> orderMap = BeanUtil.beanToMap(orders);
    
        return WxpayUtils.getPayUrl(orderMap);
    }
    
    /**
     * 校验库存
     * 先合并sku_id相同的数据，得到总的购物车，在进行库存比较
     * @param shoppingCartList
     */
    private void checkStockNum(List<ShoppingCart> shoppingCartList) {
    
        //按照sku_id进行分组操作
        Map<String, List<ShoppingCart>> skuIdShoppingCartMap = shoppingCartList.stream()
                .collect(Collectors.groupingBy(ShoppingCart::getSkuId));
    
        for (Map.Entry<String, List<ShoppingCart>> entry : skuIdShoppingCartMap.entrySet()) {
    
            String skuId = entry.getKey();
    
            List<ShoppingCart> shoppingCarts = entry.getValue();
    
            Integer skuRemainStock = shoppingCarts.get(0).getStock();
    
            int totalNum = shoppingCarts.stream()
                    .mapToInt(shoppingCart -> Integer.parseInt(shoppingCart.getCartNum()))
                    .sum();
    
            if (totalNum >= skuRemainStock){ //超过库存
                
                throw new IllegalCharacterException("商品库存不足，请调整后重试！");
                
            }
            
            //扣减库存
            ProductSku productSku = new ProductSku();
            
            productSku.setSkuId(skuId);
            productSku.setStock(skuRemainStock - totalNum);
            
            
            productSkuService.updateById(productSku);
            
        }
        
    }
    
    
}
